// JavaScript Document
var http = require('http');
var fs = require('fs');
var dao = require('./dao.js');
var timepoint = require('./timepoint.js');

/*
 * Constants
 */
var filename = 'fog1.2.6.html';
var setTimepoint = true;
var interval = 1000;

var webserver  = http.createServer( function (req, res) {
	fs.readFile(filename, 'utf8', function (err, data) {
		res.writeHead(200, { 'Content-Type': 'text/html' });
		res.end(data);
	});
});

// create socket server
var io = require('socket.io').listen(webserver);
io.set('log level', 1);

/*
 * utility functions
 */ 
var getNeighborCellIds = function(cell) {
	var ids = [
	    'g' + (cell.gridx + 1) + 'x' + (cell.gridy + 1) + 'y',
	    'g' + (cell.gridx + 2) + 'x' + (cell.gridy) + 'y',
	    'g' + (cell.gridx + 1) + 'x' + (cell.gridy - 1) + 'y',
	    'g' + (cell.gridx - 1) + 'x' + (cell.gridy - 1) + 'y',
	    'g' + (cell.gridx - 2) + 'x' + (cell.gridy) + 'y',
	    'g' + (cell.gridx - 1) + 'x' + (cell.gridy + 1) + 'y'    
	];
	
	return ids;
};

var isMasterCell = function(cell) {
	if (cell.relaArrays.nearBy[0]) return true;
	
	return false;
};

var hasNeighborCell = function(cell) {
	for (var i = 1; i < 7; i++) {
		if (cell.relaArrays.nearBy[i]) return true;
	}
	
	return false;
};

var createCell = function(id) {
	coord = id.split('x');
	var x = Number(coord[0].replace('g', ''));
	var y = Number(coord[1].replace('y', ''));
	
	var cell = new dao.GridModel({
		_id: id,
		gridx: x,
		gridy: y
	});
	
	return cell;
};

var setSlaveCell = function(cell ,masterCell) {
	cell.prop.class = "relaempty";
	cell.prop.content = null;
	cell.prop.writime = null;
	cell.prop.color = masterCell.prop.color;
	cell.prop.keyword = masterCell.prop.keyword;
	cell.prop.key_id = masterCell.prop.key_id;
	
	cell.markModified('relaArrays');
	cell.save();
};

var updateRelativeCell = function(id, cell, data, relative, nearby) {
	console.log('update relative cell... id: ' + id);
	
	if (cell == null) {
		cell = createCell(id);
	}

	if (cell.prop.class == null) {
		// if grid cell is empty
		cell.prop.class = 'relaempty';
		cell.prop.key_id = data.key_id;
		cell.prop.keyword = data.keyword;
		cell.prop.color = data.fill;
		
		cell.relaArrays.nearBy[nearby] = 1;
		cell.relaArrays.nearbyG.push(data.id);
		
		cell.markModified('relaArrays');
		cell.save();
		
		io.sockets.emit('registpushN', cell);
	}
	else {
		cell.relaArrays.nearBy[nearby] = 1;
		cell.relaArrays.nearbyG.push(data.id);
		
		cell.markModified('relaArrays');
		cell.save();
	}
};

var onNeighborRemoved = function(cell, removedCell, nearby) {
	cell.relaArrays.nearBy[nearby] = null;
	
	var index = cell.relaArrays.nearbyG.indexOf(removedCell.id);
	cell.relaArrays.nearbyG.splice(index, 1);
	
	if (!hasNeighborCell(cell)) {
		cell.prop = null;
		cell.markModified('relaArrays');
		cell.save();
		
		io.sockets.emit('removepush', cell._id);
	}
	else if (!isMasterCell(cell)) {
		var id = cell.relaArrays.nearbyG[0];
		dao.GridData.findById(id, function(err, masterCell) {
			setSlaveCell(cell, masterCell);
			io.sockets.emit('removepushN', cell);
		});
	}		
};

var findNeighbor = function(neighbors, i, handler) {
	dao.GridData.findById(neighbors[i], function(err, cell) {
		if (err) {
			console.log('error occured while finding data by id ' + neighbors[i]);
		}
		
		handler(cell, i);
//		updateRelativeCell(neighbors[i], cell, data, i + 1, i + 1);
	});
};

//app.get

//var color, keyword, content;

io.sockets.on('connection', function (socket) {
	// ajaj event which occurs document is ready on client browser
	socket.on('ajaj', function (data) {
		console.log('ajaj event occured.');
		dao.GridData.find()
			.where('gridx').gte(data.cfx-64).lt(data.cfx+64)
			.where('gridy').gte(data.cfy-24).lt(data.cfy+24)
			.where('class').in(['filled', 'relaempty', 'reserved'])
			.exec(function (err, cells){
				socket.emit('ajaj', cells);
			});
	});
	
	socket.on('reserve', function (data) {
		dao.GridData.findById(data.id, function(err, cell) {
			if (cell == null) {
				cell = createCell(data.id);
			}
			
			cell.prop.class = 'reserved';
			cell.save();
			
			console.log('data has been reserved: ' + data);	
			io.sockets.emit('reserve', cell);
		});
	});
	
	socket.on('reserveC', function (data) {
		if (data.id) {
			dao.GridData.findById(data.id, function(err, cell) {
				if (cell == null) {
					cell = createCell(data.id);
				}
				
				if (cell.prop.class != 'reserved') return;
				
				if (cell.relaArrays.nearbyG[0] == null) {
					cell.prop = null;
				}
				else {
					cell.prop.class = 'relaempty';
				}
				
				cell.save();
				
				console.log('reserveC occured: ' + cell);
				io.sockets.emit('reserveC', cell);
			});
		};
	});
	
	// handler for registering or updating a post
	socket.on('regist', function (data) {

		console.log('data has been registered:');
		console.log(data);
		
		// generate unique key
		if (data.key_id == null) {
			data.key_id = Number(new Date()) + (Math.floor(Math.random()*1000));
		}
		
		// update main cell
		dao.GridData.findById(data.id, function(err, cell) {
			if (err) {
				console.log('error occured while finding data by id ' + data.id);
			}
			
			if (cell == null) {
				cell = createCell(data.id);
			}
			
			cell.prop.color = data.fill;
			cell.prop.keyword = data.keyword;
			cell.prop.key_id = data.key_id;
			cell.prop.content = data.message;
			cell.prop.class = 'filled';
			cell.prop.writime = Number(new Date());
			
			cell.relaArrays.nearBy[0] = 1;
			
			cell.markModified('relaArrays');
			cell.save();
			
			console.log('cell: ' + JSON.stringify(data));
			dao.insertTimepoint(cell.id, timepoint.defaultPoint);			
			
			io.sockets.emit('registpush', cell);
		});
		
		// update neighbor cells
		var neighbors = [data.id4, data.id5, data.id6, data.id1, data.id2, data.id3];
		for (var i = 0; i < neighbors.length; i++) {
			findNeighbor(neighbors, i, function(cell, i) {
				updateRelativeCell(neighbors[i], cell, data, i + 1, i + 1);
			});
		}
	});
});

if (setTimepoint) {
	setInterval(function() {
		dao.TpData.find({}, function (err, tps) {
			tps.forEach(function (tp) {
				var pastLevel = tp.level;
				
				tp.level = timepoint.getTimeLevel(tp.timepoint);
				
				if (tp.level == 0) { 
					// 지워지는 좌표안으로 먼저 들어간다
					dao.GridData.findById(tp.grid_id, function(err, cell) {
						cell.relaArrays.nearBy[0] = null;
						cell.markModified('relaArrays');
						
						if (hasNeighborCell(cell)) {
							var id = cell.relaArrays.nearbyG[0];
							dao.GridData.findById(id, function(err, masterCell) {
								setSlaveCell(cell, masterCell);
								io.sockets.emit('removepushN', cell);								
							});
						} 
						else {
							cell.prop = null;
							cell.save();
							
							io.sockets.emit('removepush', cell._id);
						}
						
						var neighbors = getNeighborCellIds(cell);
						for (var i = 0; i < neighbors.length; i++) {
							findNeighbor(neighbors, i, function(neighbor, i) {
								onNeighborRemoved(neighbor, cell, i + 1);
							});
						};
					});
					tp.remove();
				}
				
				if (pastLevel != tp.level || pastLevel == null ) {
					io.sockets.emit('timepoint', tp);
				}
				
				tp.timepoint -= 1000;
				tp.save();
			});
		});
	}, interval);
}

webserver.listen(7777);